package com.team.cloudsharing.dao.folder;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.team.cloudsharing.dao.user.UserDO;
import com.team.cloudsharing.ultis.CastArrayList;

@Repository
public class FolderDAOImpl implements FolderDAO {

	final static Logger logger = Logger.getLogger(FolderDAOImpl.class);

	@Autowired
	SessionFactory sessionFactory;
	
	@Override
	public long insertFolder(FolderDO folderDO) {
		long folderId = -1;
		Session session = null;
		if (folderDO != null) {
			try {
				session = sessionFactory.openSession();
				Transaction tx = session.beginTransaction();
				session.saveOrUpdate(folderDO);
				tx.commit();
				Serializable id = session.getIdentifier(folderDO);
				folderId = (Long) id;
			} catch (Exception e) {
				logger.error(e.getMessage());
				e.printStackTrace();
			} finally {
				try {
					session.close();
				} catch (Exception e2) {
					logger.error(e2.getMessage());
				}
			}
		}
		return folderId;
	}

	@Override
	public FolderDO findFolderById(long folderId) {
		FolderDO folderDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			folderDO = (FolderDO) session.get(FolderDO.class, folderId);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return folderDO;
	}
	
	@Override
	public FolderDO findFolderByFolderUrl(String folderUrl){
		FolderDO folderDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.eq("folderUrl", folderUrl));
			folderDO = (FolderDO) criteria.uniqueResult();
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return folderDO;
	}
	
	@Override
	public FolderDO findFolderByFolderNameAndFolderPathAndUserId(String folderName, String folderPath, UserDO userDO) {
		FolderDO folderDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.eq("folderName", folderName));

			criteria.add(Restrictions.eq("folderPath", folderPath));
			criteria.add(Restrictions.eq("userDO", userDO));
			folderDO = (FolderDO) criteria.uniqueResult();
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return folderDO;
	}
	
	@Override
	public FolderDO findROOTFolderOfUser(UserDO userDO) {
		FolderDO folderDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.eq("folderIdParent", -1L));
			criteria.add(Restrictions.eq("userDO", userDO));
			folderDO = (FolderDO) criteria.uniqueResult();
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return folderDO;
	}
	
	public List<FolderDO> findAllFolderInFolder(FolderDO folderDO){
		Set<FolderDO> setFolderDOs = new LinkedHashSet<FolderDO>();
		List<FolderDO> listFolderDOs = new ArrayList<FolderDO>();
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.eq("folderIdParent", folderDO.getFolderId()));
			setFolderDOs.addAll(CastArrayList.castCollection(criteria.list(), FolderDO.class));
			listFolderDOs.addAll(setFolderDOs);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listFolderDOs;
	}
	
	@Override
	public List<FolderDO> findAllFolderByFolderPathAndUserId(String folderPath, UserDO userDO, String trashStatus) {
		Set<FolderDO> setFolderDOs = new LinkedHashSet<FolderDO>();
		List<FolderDO> listFolderDOs = new ArrayList<FolderDO>();
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.gt("folderIdParent", -1L));
			criteria.add(Restrictions.eq("folderPath", folderPath));
			if (trashStatus.equals("true") || trashStatus.equals("false")){
				boolean isTrash = Boolean.parseBoolean(trashStatus);
				criteria.add(Restrictions.eq("isFolderInTrash", isTrash));
			}
			criteria.add(Restrictions.eq("userDO", userDO));
			setFolderDOs.addAll(CastArrayList.castCollection(criteria.list(), FolderDO.class));
			listFolderDOs.addAll(setFolderDOs);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listFolderDOs;
	}

	@Override
	public long updateFolder(FolderDO folderDO) {
		return insertFolder(folderDO);
//		long statusUpdate = -1;
//		Session session = null;
//		if (folderDO != null) {
//			try {
//				session = sessionFactory.openSession();
//				Transaction tx = session.beginTransaction();
//				session.saveOrUpdate(folderDO);
//				tx.commit();
//				Serializable id = session.getIdentifier(folderDO);
//				statusUpdate = (Long) id;
//			} catch (Exception e) {
//				logger.error(e.getMessage());
//				e.printStackTrace();
//			} finally {
//				try {
//					session.close();
//				} catch (Exception e2) {
//					logger.error(e2.getMessage());
//				}
//			}
//		}
//		return statusUpdate;
	}

	@Override
	public boolean deleteFolder(long folderId) {
		boolean statusDelete = false;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			FolderDO folderDO = (FolderDO) session.get(FolderDO.class, folderId);
			Transaction tx = session.getTransaction();
			session.beginTransaction();
			session.delete(folderDO);
			tx.commit();
			statusDelete = true;
		} catch (Exception e) {
			statusDelete = false;
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return statusDelete;
	}

	@Override
	public List<String> getFolderNamesHasFoderIdParent(long folderIdParent) {
		List<String> folderNames = new ArrayList<String>();
		Session session = null;
		try {
			session = sessionFactory.openSession();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.eq("folderIdParent", folderIdParent));
			List<FolderDO> folderDOs = CastArrayList.castCollection(criteria.list(), FolderDO.class);
			for (FolderDO folderDO : folderDOs) {
				folderNames.add(folderDO.getFolderName());
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return folderNames;
	}

	@Override
	public long getFolderIdByFolderNameAndFolderIdParent(String folderName,
			long folderIdParent) {
		FolderDO folderDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.eq("folderName", folderName));
			criteria.add(Restrictions.eq("folderIdParent", folderIdParent));
			folderDO = (FolderDO) criteria.uniqueResult();
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return folderDO.getFolderId();
	}
	
	@Override
	public List<FolderDO> findFolderByFolderNameAndUserId(String folderName, UserDO userDO) {
		Set<FolderDO> setFolderDOs = new LinkedHashSet<FolderDO>();
		List<FolderDO> listFolderDOs = new ArrayList<FolderDO>();
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.like("folderName", folderName, MatchMode.ANYWHERE));
			criteria.add(Restrictions.eq("userDO", userDO));
			criteria.add(Restrictions.eq("isFolderInTrash", false));
			criteria.add(Restrictions.gt("folderIdParent", -1L));
			setFolderDOs.addAll(CastArrayList.castCollection(criteria.list(), FolderDO.class));
			listFolderDOs.addAll(setFolderDOs);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listFolderDOs;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<FolderDO> findAllFolderByUserId(UserDO userDO) {
		
		List<FolderDO> listFolderDOs = null;
		Session session = sessionFactory.openSession();
		List<BigInteger> listFolderId = null;
		try {
			Long userId = userDO.getUserId();
			String searchQuery = "Select folder_id from folder where folder.user_id=:userId";
			SQLQuery query = session.createSQLQuery(searchQuery.toString());
			query.setParameter("userId", userId);
			listFolderId = query.list();
			listFolderDOs = new ArrayList<FolderDO>();
			for(BigInteger folderId : listFolderId){
				listFolderDOs.add(findFolderById(folderId.longValue()));
			}
			
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listFolderDOs;
		
	}

	@Override
	public List<FolderDO> findAllFolderWithTrashStatusByUserId(UserDO userDO, String trashStatus) {
		Set<FolderDO> setFolderDOs = new LinkedHashSet<FolderDO>();
		List<FolderDO> listFolderDOs = new ArrayList<FolderDO>();
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.gt("folderIdParent", -1L));
			if (trashStatus.equals("true") || trashStatus.equals("false")){
				boolean isTrash = Boolean.parseBoolean(trashStatus);
				criteria.add(Restrictions.eq("isFolderInTrash", isTrash));
			}
			criteria.add(Restrictions.eq("userDO", userDO));
			setFolderDOs.addAll(CastArrayList.castCollection(criteria.list(), FolderDO.class));
			listFolderDOs.addAll(setFolderDOs);
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listFolderDOs;
	}

	@Override
	public List<FolderDO> findAllFolderByFolderNamePatternInFolder(String folderNamePattern, FolderDO folderDO) {
		List<FolderDO> folderDOs = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FolderDO.class);
			criteria.add(Restrictions.like("folderName", folderNamePattern));
			criteria.add(Restrictions.eq("folderIdParent", folderDO.getFolderId()));
			folderDOs = CastArrayList.castCollection(criteria.list(), FolderDO.class);
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return folderDOs;
	}

}
